home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The 640 MEG Shareware Studio 2
/
The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO
/
clang
/
16550.zip
/
FACT.C
< prev
next >
Wrap
Text File
|
1991-07-20
|
14KB
|
435 lines
/* FFFFFFF A CCCCCC TTTTTTTTTTT CCCCCC
* F A A C T C
* FFFFF A A C T C
* F A AAA A C T C
* F A A C T .. C
* F A A CCCCCC T .. CCCCCC
*
* FACT.C -- FIFO Asynchronous Communication Test Program for
* NS16550 and NS16552 UARTs
*
* Greg DeJager Ver 1.0 1/31/89
*
* Adapted from LBT.C -- LoopBack Test Rev 1.1
* Developed By: Brian A. Berg
* Berg Software Design
* October 1988
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <dos.h>
#include "stdhdr.h"
#include "serio.h"
/* define some macros for use herein */
/* program test name for user prompt and help screen */
#define TESTNAME "NS16550/NS16552 FIFO Asynchronous Communications Test (FACT)"
/* clear the RBR, LSR and IIR registers (used at start and before exit) */
#define CLEAR_REGS() ((void)rdRBR(), (void)rdRBR(), \
(void)rdLSR(), (void)rdIIR(), (void)wrMCR(0), \
(void)wrFCR(CLR_FIFO))
/* GET ctrl-break/ctrl-c checking flag status via "INT 21H" */
#define GETBRK() (regs.h.ah = 0x33, regs.h.al = 0, \
intdos(®s, ®s), regs.h.dl)
/* SET ctrl-break/ctrl-c checking flag to argument via "INT 21H" */
#define SETBRK(brk) (regs.h.ah = 0x33, regs.h.al = 1, \
regs.h.dl = (brk), intdos(®s, ®s))
/* COMx-dependent parameters */
UINT comvnum[COM_CNT] = {0x0C, 0x0B, 0x0B}; /* int. vector nos. for COMx */
UINT uartbadd[COM_CNT] = {0x3F8, 0x2F8, 0x3220}; /* UART base adds. for COMx */
UINT picmsk[COM_CNT] = {0xEF, 0xF7, 0xF7}; /* PIC masks for COMx: IRQ4,3 */
/* declare parameters and default values; override via invocation line args. */
/* argument 1: COM number */
int com = COM_DEF;
UINT ivnum; /* int. vector number (set as comvnum[com-1]) */
UINT ubase; /* UART base address (set as uartbadd[com-1]) */
/* argument 2: baud rate divisor */
int baudiv = BAUDIV_DEF;
UCHAR bytwr = 0; /* write byte counter (goes from 0 to 255) */
UCHAR bytrd = 0; /* read byte counter (goes from 0 to 255) */
UCHAR iir, lsr; /* storage for IIR and LSR */
UCHAR bytin; /* input byte storage */
UINT errflag = FALSE; /* error indication and ID */
/* storage for original environment parameters */
void far *savect; /* interrupt vector */
UCHAR savbrk; /* ctrl-break flag */
UINT savmsk; /* PIC mask */
UCHAR savier; /* IER register */
UCHAR savlcr; /* LCR register */
UCHAR savmcr; /* MCR register */
UCHAR savdll; /* DLL register */
UCHAR savdlm; /* DLM register */
CNVTR cnvtr; /* handy union for data type conversions */
union REGS regs; /* 16- and 8-bit registers for intdos() */
int finit = FALSE; /* boolean for program termination */
/* globals which control the tick mark on the screen */
int tick = FALSE; /* boolean for display of "tick" on CRT */
int tick_ff = 0; /* tick flip-flop (either 0 or 1) */
int bytick = 0; /* helps determine when to set tick boolean */
UCHAR *tickstr[] = {"\b*", "\b$"}; /* "tick" mark strings */
/* Routines contained herein: */
void main(int, char **); /* main program */
void interrupt far serint(void); /* serial interrupt handler */
void procarg(int, char **); /* process invocation arguments */
void savepar(void); /* save our environment parameters */
void rstrpar(void); /* restore our environment parameters */
void dspstr(UCHAR *); /* display a string to console */
void usage(void); /* display usage info and exit */
/*
* main(): main program
*/
void main(argc, argv)
int argc;
char **argv;
{
/* process invocation args., and set up int vector no. and UART base add */
procarg(argc, argv); /* get com# and baudrate from argument string */
CLEAR_REGS(); /* clear RBR, LSR, IIR, MCR, and FIFOs */
savepar(); /* save our environment parameters */
/* set baud rate */
wrLCR(0x80); /* set DLAB */
cnvtr.intval[0] = baudiv;
outp(DLL, cnvtr.chrval[0]);
outp(DLM, cnvtr.chrval[1]);
wrLCR(0x0B); /* 8 data, 1 stop, odd parity */
printf("\n\n %s\n\n",TESTNAME); /*startup message*/
/* wait loop to insure other machine has cleared its registers */
printf("\nHit a key when other program has been started.\n\n");
while( !(kbhit() && getch()) );
/* set up registers for our environment */
wrFCR(CLR_FIFO); /* clear transmitter and receiver FIFOs */
wrFCR(FIFO_EN); /* enable FIFOs, set Rx trigger at 14 bytes */
if ( (rdIIR() & 0xc0) != 0xc0) /* ensure FIFOs present */
{
printf("\nFatal Error. FIFOs not present\n");
errflag = ENDPROG;
}
wrMCR(OUT2); /* enable PIC interrupt (OUT2) */
wrIER(IER_VAL1); /* Enable LSI and RDAI */
wrMCR(0x0a); /* Assert RTS (and OUT2) */
printf("Waiting for first 'Request To Send' from other machine...\n\n");
while (!(rdMSR() & CTS)); /* wait for other machine to assert RTS */
printf("\n\nHit non-control key to stop: ");
/* Enable Tx interupts; loop until int. handler finished or any key struck */
wrIER(IER_VAL2);
while (!errflag)
{
if (kbhit() && getch())
errflag = ENDPROG;
if (tick) /* display tick mark */
{
/* display the tick mark */
printf("%s",tickstr[tick_ff]);
tick_ff = 1 - tick_ff; /* update tick flip-flop */
tick = FALSE;
}
}
wrIER(0); /* disable UART interrupts */
while ( !(rdLSR() & TEMT) ); /* wait for Tx FIFO to clear */
CLEAR_REGS(); /* clear RBR, LSR, MCR and IIR registers before we exit */
/* Output error message represented by 'errflag' variable */
switch (errflag)
{
case ENDPROG: /* keyboard hit or fatal error */
break;
case FALSEINT: /* IIR shows no interrupt active */
printf("\nFalse interrupt. No UART interrupt active.\n");
break;
case STATUSERR: /* Line Status interrupt generated */
printf("\nLine Status interrupt. LSR = %x\n",lsr);
printf("Byte causing LSI = %x\n",bytin);
break;
case MISMATCH: /* Data received did not match data expected */
printf("\nData mismatch\n");
printf("Byte expected = %x\n",--bytrd);
printf("Byte received = %x\n",bytin);
break;
case RX_ERROR: /* RDAI generated but DR was not set */
printf("\nError: RDAI but no DR indication\n");
break;
case TX_ERROR: /* THREI generated but THRE was not set */
printf("\nError: THREI but no THRE indication\n");
break;
case IIR_ERROR: /* Invalid IIR */
printf("\nIIR invalid\n");
break;
case TIMEOUT: /* Character Timeout Interrupt */
printf("\nCharacter Timeout.\n");
break;
case TIMEOUT_ERR: /* False Character Timeout Interrupt */
printf("\nError: False Character Timeout Interrupt.\n");
break;
default:
break;
} /* end of switch */
rstrpar(); /* restore our environment parameters */
printf("\n\n\nEnd of program; Environment parameters restored.\n");
} /* end of main() */
/*
* serint(): serial port interrupt handler
*/
void interrupt far serint()
{
int bytecnt=0;
/* if errflag has been set, ignore the interrupt */
if (errflag)
{
wrIER(0);
outp(PICTRL, EOI); /* send EOI to 8259A PIC */
return;
}
/* here's the code to handle each of the various interrupt types */
switch (iir = rdIIR())
{
case F_NOIP: /* NO Interrupt Pending */
errflag = FALSEINT;
break;
case F_RLST: /* Receiver Line STatus interrupt */
lsr = rdLSR();
bytin = rdRBR(); /* read byte with error */
errflag = STATUSERR;
break;
case F_RDAV: /* Received Data AVailable */
wrMCR(OUT2); /* clear RTS */
lsr = rdLSR();
/* read bytes from FIFO and compare them with expected values */
while (rdLSR() & DR)
{
bytin = rdRBR();
if (bytin != bytrd++)
{
errflag = MISMATCH;
break; /* error, stop reading FIFO */
}
else
/* display "tick" after reading 2560 bytes */
if (!bytrd && ++bytick == 10)
{
bytick = 0;
tick = TRUE; /* turn on "tick" boolean */
}
}
if (!errflag)
wrMCR(0x0a); /* reassert RTS */
break;
case F_IIR_THRE: /* Transmitter Holding Register Empty */
lsr = rdLSR();
bytecnt = 0;
if (lsr & LSR_THRE)
{
while (rdMSR() & CTS) /* while CTS, fill FIFO */
if (bytecnt++ <= 15)
wrTHR(bytwr++);
else
break;
}
else
errflag = TX_ERROR; /* THREI without THRE set */
break;
case F_CHR_TIMEOUT: /* no characters received for 4 character times */
errflag = TIMEOUT;
if (rdLSR() & DR)
while (rdLSR() & DR) /* clear all of FIFO */
{
bytin = rdRBR();
if (bytin != bytrd++)
{
errflag = MISMATCH;
break; /* error, stop reading FIFO */
}
}
else
errflag = TIMEOUT_ERR; /* false timeout interrupt */
break;
default: /* IIR default case: FATAL ERROR */
errflag = IIR_ERROR;
break;
}
/* Toggle INTR line of UART to create edge if multiple ints pending */
wrIER(0);
if (!errflag)
wrIER(IER_VAL2);
outp(PICTRL, EOI); /* send EOI to 8259A PIC */
} /* end of serint() */
/*
* procarg(): process invocation arguments
*/
void procarg(argc, argv)
int argc;
char **argv;
{
int badarg = TRUE; /* boolean: improper invocation arg. */
switch (argc)
{
case 3: /* baud rate divisor */
baudiv = atoi(argv[2]);
if (!MN_MX(baudiv, BAUDIV_MIN, BAUDIV_MAX))
break;
case 2: /* COM number */
com = atoi(argv[1]);
if (!MN_MX(com, COM_MIN, COM_MAX))
break;
case 1: /* no arguments => go with defaults */
badarg = FALSE;
break;
default: /* illegal argument count */
break;
}
if (badarg)
usage(); /* never returns */
/* set up interrupt vector number and UART base address */
ivnum = comvnum[com-1];
ubase = uartbadd[com-1];
/* verify existence of COM port */
savlcr = (UCHAR)inp(LCR); /* save original LCR */
wrLCR(0x33); /* write test value to LCR */
if (inp(LCR) != 0x33)
{
printf("FATAL ERROR: COM%d not present\n", com);
exit(1);
}
} /* end of procarg() */
/*
* savepar(): save our environment parameters
*/
void savepar()
{
/* handle interrupt vector: save original and plug in our own address */
savect = _dos_getvect(ivnum); /* save original int. vector */
_dos_setvect(ivnum, serint);
/* handle ctrl-break/ctrl-c status: save original flag and disable it */
savbrk = GETBRK();
SETBRK(0);
/* handle PIC mask: save original mask and allow COMx to interrupt */
savmsk = inp(PICMSK);
outp(PICMSK, inp(PICMSK) & picmsk[com-1]);
/* save registers */
/* NOTE: LCR already saved in procarg() */
wrLCR(0x80); /* set DLAB */
savdll = (UCHAR)inp(DLL); /* save baud */
savdlm = (UCHAR)inp(DLM); /* rate */
savier = (UCHAR)inp(IER); /* save original IER */
} /* end of savepar() */
/*****************************************************************************/
/*
* rstrpar(): restore our environment parameters
*/
void rstrpar()
{
/* restore registers */
outp(LCR, 0x80); /* set DLAB */
outp(DLL, savdll); /* restore baud */
outp(DLM, savdlm); /* rate */
outp(LCR, 0); /* clear DLAB */
outp(IER, savier);
outp(LCR, savlcr);
/* restore original address to interrupt vector */
_dos_setvect(ivnum, savect);
/* restore original ctrl-break/ctrl-c checking flag */
SETBRK(savbrk);
/* restore original PIC mask */
outp(PICMSK, savmsk);
} /* end of rstrpar() */
/*****************************************************************************/
/*
* usage(): display program usage information and terminate (never return)
*/
void usage()
{
printf("\n** HELP Screen for %s **\n\n", TESTNAME);
printf("USAGE: fact [<COM-number> [<baudrate-divisor>]]\n");
printf(" arg1 arg2 \n");
printf(" ('fact' may be followed by no args, arg1, or arg1+2)\n\n");
printf(" ARGUMENT MINIMUM VALUE MAXIMUM VALUE DEFAULT VALUE \n");
printf("============ =============== =============== ==============\n");
printf(" COM-number %d (for COM%d) %d (for COM%d) %d \n",
COM_MIN, COM_MIN, COM_MAX, COM_MAX, COM_DEF);
printf(" (serial line %d) (serial line %d) (COM%d)\n\n",
COM_MIN-1, COM_MAX-1, COM_DEF);
printf(" baudrate- %d (56000 baud) %d (%ld baud) %4d \n",
BAUDIV_MIN, BAUDIV_MAX, BAUDRATE(BAUDIV_MAX), BAUDIV_DEF);
printf(" divisor (based on 1.8432 MHz crystal) (%ld baud) \n",
BAUDRATE(BAUDIV_DEF));
printf(" * Sample baudrate divisors: for baud= 1200, use 96 * \n");
printf(" * 2400 48 * \n");
printf(" * 4800 24 * \n");
printf(" * 9600 12 * \n");
printf(" * 19200 6 * \n");
exit(1);
} /* end of usage() */
/* end of act.c */